
#include "DictionaryCracker.h"
#include <math.h>
CDictionaryCracker::CDictionaryCracker(void)
{
	m_nPassTried = 0;
	m_vHashList = NULL;
	m_vWordList = NULL;
}

CDictionaryCracker::~CDictionaryCracker(void)
{
	if(m_vHashList != NULL)
	{
		for(int i = 0; i > m_vHashList->size(); i++)
		{
			unsigned char *pHash = (*m_vHashList)[i];
			m_vHashList->erase(m_vHashList->begin() + i);
			delete pHash;
			i--;
		}
		delete m_vHashList;
	}
	if(m_vWordList != NULL)
		delete m_vWordList;
}


void CDictionaryCracker::ReverseString(char *str, int nLen)
{
     for(int y = nLen; y >= (nLen/2)+1; y--) //for loop arranging the string
     {
          swap(str[nLen-y],str[y-1]); // swaps letters
     }
}
void CDictionaryCracker::StringToUpper(char *str, int nLen)
{//change each element of the string to upper case
	for(int i=0; i < nLen;i++)
    {
		str[i] = toupper(str[i]);
	}
}

void CDictionaryCracker::StringToLower(char *str, int nLen)
{
	//change each element of the string to upper case    
	for(int i=0; i < nLen;i++)
    {
		str[i] = tolower(str[i]);
	}
}


void CDictionaryCracker::SetDictionary(WORDLIST *vWordList)
{
	if(m_vWordList != NULL)
	{
		m_vWordList->clear();
		delete m_vWordList;
	}
	m_vWordList = vWordList;
}
void CDictionaryCracker::SetHashList(HASHLIST *vHashList, int nHashLen, HASHROUTINE pHashFunc)
{
	if(m_vHashList != NULL)
	{
		for(int i = m_vHashList->size() - 1; i > 0; i--)
		{
			unsigned char *pHash = (*m_vHashList)[i];
			m_vHashList->erase(m_vHashList->begin() + i);
			delete pHash;
		}

		delete m_vHashList;
	}
	m_vHashList = vHashList;
	m_nHashLen = nHashLen;
	m_pHashFunc = pHashFunc;
}

void CDictionaryCracker::Start(CBPASSCRACKED pPassCracked, int nOptions)
{
	m_pPassCracked = pPassCracked;
	unsigned char hash[16] = {0};
	int nWord = 0;
	for(WORDLIST::iterator i = m_vWordList->begin(); i < m_vWordList->end(); i++)
	{
		nWord++;
		const char *pWord = i->c_str();
		int nLen = i->length();
		if(nOptions & OPT_ASIS)
		{
			m_pHashFunc((unsigned char *)pWord, nLen, hash);
			CheckPassword(hash, (char *)pWord, nLen);
		}
		if(!(nOptions & OPT_CASEPERM)) // No idea in doing lcase, ucase and tcase if we are doing case permutation
		{
			if(nOptions & OPT_UPPERCASE)
			{
				char *tmp = new char[nLen + 1];
				memcpy(tmp, pWord, nLen);
				StringToUpper(tmp, nLen);
				m_pHashFunc((unsigned char*)tmp, nLen, hash);
				CheckPassword(hash, tmp, nLen);
				delete tmp;
			}
			if(nOptions & OPT_LOWERCASE)
			{
				char *tmp = new char[nLen + 1];
				memcpy(tmp, pWord, nLen);
				StringToLower(tmp, nLen);
				m_pHashFunc((unsigned char*)tmp, nLen, hash);
				CheckPassword(hash, tmp, nLen);
				delete tmp;
			}
			if(nOptions & OPT_TITLECASE)
			{
				char *tmp = new char[nLen + 1];
				memcpy(tmp, pWord, nLen);
				tmp[0] = toupper(tmp[0]);
				m_pHashFunc((unsigned char*)tmp, nLen, hash);
				CheckPassword(hash, tmp, nLen);
				delete tmp;
			}
		}
		else // case permutation == true
		{
			char *tmp = new char[nLen + 1];
			memcpy(tmp, pWord, nLen);
			StringToLower(tmp, nLen);
			int nTries = (int)pow(2.0, nLen);
			int nLetter = 0;
			for(int j = 0; j < nTries; j++)
			{
				int f = 1;
				for(int g = 0; g < nLen; g++)
				{
					if(j & f)
						tmp[g] = toupper(tmp[g]);
					else tmp[g] = tolower(tmp[g]);
					f *= 2;
				}
				m_pHashFunc((unsigned char*)tmp, nLen, hash);
				CheckPassword(hash, tmp, nLen);
			}
			delete tmp;
		}

	}
}

void CDictionaryCracker::CheckPassword(unsigned char *pHash, char *pWord, int nLen)
{
	m_nPassTried++;	
	int nNum = 0;
	for(HASHLIST::iterator i = m_vHashList->begin(); i < m_vHashList->end(); i++)
	{
		if(memcmp((const char*)pHash, *i, m_nHashLen) == 0)
		{
			string sHash;
			Bin2Hash(pHash, 16, sHash);
			m_pPassCracked((char*)sHash.c_str(), string((char*)pWord, nLen)); // Remember to change it to hex chars of pHash
			//m_vHashList.erase(m_vHashList.begin() + nNum, m_vHashList.begin() + nNum + 1);
			nNum--;
		}
		nNum++;
	}
}
